/**
 ******************************************************************************
 * @file    hw_uart.c
 * @author  MCD Application Team
 * @brief   hardware access
 ******************************************************************************
 * @attention
 *
 * <h2><center>&copy; Copyright (c) 2019 STMicroelectronics.
 * All rights reserved.</center></h2>
 *
 * This software component is licensed by ST under Ultimate Liberty license
 * SLA0044, the "License"; You may not use this file except in compliance with
 * the License. You may obtain a copy of the License at:
 *                             www.st.com/SLA0044
 *
 ******************************************************************************
 */


/* Includes ------------------------------------------------------------------*/
#include "app_common.h"
#include "hw_conf.h"

/* Macros --------------------------------------------------------------------*/
#define HW_UART_INIT(__HANDLE__, __USART_BASE__)                                                    \
        do{                                                                                         \
            (__HANDLE__).Instance = (__USART_BASE__);                                               \
            (__HANDLE__).Init.BaudRate  = CFG_HW_##__USART_BASE__##_BAUDRATE;                       \
            (__HANDLE__).Init.WordLength = CFG_HW_##__USART_BASE__##_WORDLENGTH;                    \
            (__HANDLE__).Init.StopBits = CFG_HW_##__USART_BASE__##_STOPBITS;                        \
            (__HANDLE__).Init.Parity = CFG_HW_##__USART_BASE__##_PARITY;                            \
            (__HANDLE__).Init.HwFlowCtl = CFG_HW_##__USART_BASE__##_HWFLOWCTL;                      \
            (__HANDLE__).Init.Mode = CFG_HW_##__USART_BASE__##_MODE;                                \
            (__HANDLE__).Init.OverSampling = CFG_HW_##__USART_BASE__##_OVERSAMPLING;                \
            (__HANDLE__).AdvancedInit.AdvFeatureInit = CFG_HW_##__USART_BASE__##_ADVFEATUREINIT;    \
            HAL_UART_Init(&(__HANDLE__));                                                           \
        } while(0)

#define HW_UART_RX_IT(__HANDLE__, __USART_BASE__)                                                   \
        do{                                                                                         \
            HW_##__HANDLE__##RxCb = cb;                                                             \
            (__HANDLE__).Instance = (__USART_BASE__);                                               \
            HAL_UART_Receive_IT(&(__HANDLE__), p_data, size);                                       \
        } while(0)

#define HW_UART_TX_IT(__HANDLE__, __USART_BASE__)                                                   \
        do{                                                                                         \
            HW_##__HANDLE__##TxCb = cb;                                                             \
            (__HANDLE__).Instance = (__USART_BASE__);                                               \
            HAL_UART_Transmit_IT(&(__HANDLE__), p_data, size);                                      \
        } while(0)

#define HW_UART_TX(__HANDLE__, __USART_BASE__)                                                      \
        do{                                                                                         \
            (__HANDLE__).Instance = (__USART_BASE__);                                               \
            hal_status = HAL_UART_Transmit(&(__HANDLE__), p_data, size, timeout);                   \
        } while(0)

#define HW_UART_MSP_UART_INIT(__HANDLE__, __USART_BASE__)                                           \
        do{                                                                                         \
                                                                                                    \
            /* Configure Tx Pin */                                                                  \
            CFG_HW_##__USART_BASE__##_TX_PORT_CLK_ENABLE();                                         \
                                                                                                    \
            GPIO_InitStruct.Pin = CFG_HW_##__USART_BASE__##_TX_PIN ;                                \
            GPIO_InitStruct.Mode = CFG_HW_##__USART_BASE__##_TX_MODE;                               \
            GPIO_InitStruct.Pull = CFG_HW_##__USART_BASE__##_TX_PULL;                               \
            GPIO_InitStruct.Speed = CFG_HW_##__USART_BASE__##_TX_SPEED;                             \
            GPIO_InitStruct.Alternate = CFG_HW_##__USART_BASE__##_TX_ALTERNATE;                     \
            HAL_GPIO_Init(CFG_HW_##__USART_BASE__##_TX_PORT, &GPIO_InitStruct);                     \
                                                                                                    \
                                                                                                    \
            /* Configure Rx Pin */                                                                  \
            CFG_HW_##__USART_BASE__##_RX_PORT_CLK_ENABLE();                                         \
                                                                                                    \
            GPIO_InitStruct.Pin = CFG_HW_##__USART_BASE__##_RX_PIN;                                 \
            GPIO_InitStruct.Mode = CFG_HW_##__USART_BASE__##_RX_MODE;                               \
            GPIO_InitStruct.Pull = CFG_HW_##__USART_BASE__##_RX_PULL;                               \
            GPIO_InitStruct.Speed = CFG_HW_##__USART_BASE__##_RX_SPEED;                             \
            GPIO_InitStruct.Alternate = CFG_HW_##__USART_BASE__##_RX_ALTERNATE;                     \
            HAL_GPIO_Init(CFG_HW_##__USART_BASE__##_RX_PORT, &GPIO_InitStruct);                     \
                                                                                                    \
                                                                                                    \
            /* Configure CTS Pin */                                                                 \
            CFG_HW_##__USART_BASE__##_CTS_PORT_CLK_ENABLE();                                        \
                                                                                                    \
            GPIO_InitStruct.Pin = CFG_HW_##__USART_BASE__##_CTS_PIN;                                \
            GPIO_InitStruct.Mode = CFG_HW_##__USART_BASE__##_CTS_MODE;                              \
            GPIO_InitStruct.Pull = CFG_HW_##__USART_BASE__##_CTS_PULL;                              \
            GPIO_InitStruct.Speed = CFG_HW_##__USART_BASE__##_CTS_SPEED;                            \
            GPIO_InitStruct.Alternate = CFG_HW_##__USART_BASE__##_CTS_ALTERNATE;                    \
            HAL_GPIO_Init(CFG_HW_##__USART_BASE__##_CTS_PORT, &GPIO_InitStruct);                    \
                                                                                                    \
            /* Set USART source clock */                                                            \
            __HAL_RCC_##__USART_BASE__##_CONFIG(CFG_HW_##__USART_BASE__##_SOURCE_CLOCK);            \
                                                                                                    \
            /* Enable USART clock */                                                                \
            __HAL_RCC_##__USART_BASE__##_CLK_ENABLE();                                              \
                                                                                                    \
            HAL_NVIC_SetPriority(__USART_BASE__##_IRQn, CFG_HW_##__USART_BASE__##_PREEMPTPRIORITY, CFG_HW_##__USART_BASE__##_SUBPRIORITY); \
            HAL_NVIC_EnableIRQ(__USART_BASE__##_IRQn);                                              \
        } while(0)

#define HW_UART_MSP_TX_DMA_INIT(__HANDLE__, __USART_BASE__)                                         \
        do{                                                                                         \
            /* Configure the DMA handler for Transmission process */                                \
        /* Enable DMA clock */                                                                      \
        CFG_HW_##__USART_BASE__##_DMA_CLK_ENABLE();                                                 \
        /* Enable DMA MUX clock */                                                                  \
        CFG_HW_##__USART_BASE__##_DMAMUX_CLK_ENABLE();                                              \
                                                                                                    \
        HW_hdma_##__HANDLE__##_tx.Instance                 = CFG_HW_##__USART_BASE__##_TX_DMA_CHANNEL; \
        HW_hdma_##__HANDLE__##_tx.Init.Request             = CFG_HW_##__USART_BASE__##_TX_DMA_REQ;  \
        HW_hdma_##__HANDLE__##_tx.Init.Direction           = DMA_MEMORY_TO_PERIPH;                  \
        HW_hdma_##__HANDLE__##_tx.Init.PeriphInc           = DMA_PINC_DISABLE;                      \
        HW_hdma_##__HANDLE__##_tx.Init.MemInc              = DMA_MINC_ENABLE;                       \
        HW_hdma_##__HANDLE__##_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;                   \
        HW_hdma_##__HANDLE__##_tx.Init.MemDataAlignment    = DMA_MDATAALIGN_BYTE;                   \
        HW_hdma_##__HANDLE__##_tx.Init.Mode                = DMA_NORMAL;                            \
        HW_hdma_##__HANDLE__##_tx.Init.Priority            = DMA_PRIORITY_LOW;                      \
                                                                                                    \
        HAL_DMA_Init(&HW_hdma_##__HANDLE__##_tx);                                                   \
                                                                                                    \
        /* Associate the initialized DMA handle to the UART handle */                               \
        __HAL_LINKDMA(huart, hdmatx, HW_hdma_##__HANDLE__##_tx);                                    \
                                                                                                    \
        /* NVIC configuration for DMA transfer complete interrupt  */                               \
        HAL_NVIC_SetPriority(CFG_HW_##__USART_BASE__##_TX_DMA_IRQn, CFG_HW_##__USART_BASE__##_DMA_TX_PREEMPTPRIORITY, CFG_HW_##__USART_BASE__##_DMA_TX_SUBPRIORITY); \
        HAL_NVIC_EnableIRQ(CFG_HW_##__USART_BASE__##_TX_DMA_IRQn);                                  \
    } while(0)

        /* Variables ------------------------------------------------------------------*/
#if (CFG_HW_USART1_ENABLED == 1)
        UART_HandleTypeDef huart1 = {0};
#if (CFG_HW_USART1_DMA_TX_SUPPORTED == 1)
    DMA_HandleTypeDef HW_hdma_huart1_tx ={0};
#endif
    void (*HW_huart1RxCb)(void);
    void (*HW_huart1TxCb)(void);
#endif

#if (CFG_HW_LPUART1_ENABLED == 1)
    UART_HandleTypeDef lpuart1 = {0};
#if (CFG_HW_LPUART1_DMA_TX_SUPPORTED == 1)
    DMA_HandleTypeDef HW_hdma_lpuart1_tx ={0};
#endif
    void (*HW_lpuart1RxCb)(void);
    void (*HW_lpuart1TxCb)(void);
#endif

    void HW_UART_Init(hw_uart_id_t hw_uart_id)
    {
        switch (hw_uart_id)
        {
#if (CFG_HW_USART1_ENABLED == 1)
            case hw_uart1:
                HW_UART_INIT(huart1, USART1);
                break;
#endif

#if (CFG_HW_LPUART1_ENABLED == 1)
            case hw_lpuart1:
                HW_UART_INIT(lpuart1, LPUART1);
                break;
#endif

            default:
                break;
        }

        return;
    }

    void HW_UART_Receive_IT(hw_uart_id_t hw_uart_id, uint8_t *p_data, uint16_t size, void (*cb)(void))
    {
        switch (hw_uart_id)
        {
#if (CFG_HW_USART1_ENABLED == 1)
            case hw_uart1:
                HW_UART_RX_IT(huart1, USART1);
                break;
#endif

#if (CFG_HW_LPUART1_ENABLED == 1)
            case hw_lpuart1:
                HW_UART_RX_IT(lpuart1, LPUART1);
                break;
#endif

            default:
                break;
        }

        return;
    }

    void HW_UART_Transmit_IT(hw_uart_id_t hw_uart_id, uint8_t *p_data, uint16_t size,  void (*cb)(void))
    {
        switch (hw_uart_id)
        {
#if (CFG_HW_USART1_ENABLED == 1)
            case hw_uart1:
                HW_UART_TX_IT(huart1, USART1);
                break;
#endif

#if (CFG_HW_LPUART1_ENABLED == 1)
            case hw_lpuart1:
                HW_UART_TX_IT(lpuart1, LPUART1);
                break;
#endif

            default:
                break;
        }

        return;
    }

    hw_status_t HW_UART_Transmit(hw_uart_id_t hw_uart_id, uint8_t *p_data, uint16_t size,  uint32_t timeout)
    {
        HAL_StatusTypeDef hal_status = HAL_OK;
        hw_status_t hw_status = hw_uart_ok;

        switch (hw_uart_id)
        {
#if (CFG_HW_USART1_ENABLED == 1)
            case hw_uart1:
                HW_UART_TX(huart1, USART1);
                break;
#endif

#if (CFG_HW_LPUART1_ENABLED == 1)
            case hw_lpuart1:
                HW_UART_TX(lpuart1, LPUART1);
                break;
#endif

            default:
                break;
        }

        switch (hal_status)
        {
            case HAL_OK:
                hw_status = hw_uart_ok;
                break;

            case HAL_ERROR:
                hw_status = hw_uart_error;
                break;

            case HAL_BUSY:
                hw_status = hw_uart_busy;
                break;

            case HAL_TIMEOUT:
                hw_status = hw_uart_to;
                break;

            default:
                break;
        }

        return hw_status;
    }

    hw_status_t HW_UART_Transmit_DMA(hw_uart_id_t hw_uart_id, uint8_t *p_data, uint16_t size, void (*cb)(void))
    {
        HAL_StatusTypeDef hal_status = HAL_OK;
        hw_status_t hw_status = hw_uart_ok;

        switch (hw_uart_id)
        {
#if (CFG_HW_USART1_ENABLED == 1)
            case hw_uart1:
                HW_huart1TxCb = cb;
                huart1.Instance = USART1;
                hal_status = HAL_UART_Transmit_DMA(&huart1, p_data, size);
                break;
#endif

#if (CFG_HW_USART2_ENABLED == 1)
            case hw_uart2:
                HW_huart2TxCb = cb;
                huart2.Instance = USART2;
                hal_status = HAL_UART_Transmit_DMA(&huart2, p_data, size);
                break;
#endif

#if (CFG_HW_LPUART1_ENABLED == 1)
            case hw_lpuart1:
                HW_lpuart1TxCb = cb;
                lpuart1.Instance = LPUART1;
                hal_status = HAL_UART_Transmit_DMA(&lpuart1, p_data, size);
                break;
#endif

            default:
                break;
        }

        switch (hal_status)
        {
            case HAL_OK:
                hw_status = hw_uart_ok;
                break;

            case HAL_ERROR:
                hw_status = hw_uart_error;
                break;

            case HAL_BUSY:
                hw_status = hw_uart_busy;
                break;

            case HAL_TIMEOUT:
                hw_status = hw_uart_to;
                break;

            default:
                break;
        }

        return hw_status;
    }

    void HW_UART_Interrupt_Handler(hw_uart_id_t hw_uart_id)
    {
        switch (hw_uart_id)
        {
#if (CFG_HW_USART1_ENABLED == 1)
            case hw_uart1:
                HAL_UART_IRQHandler(&huart1);
                break;
#endif

#if (CFG_HW_LPUART1_ENABLED == 1)
            case hw_lpuart1:
                HAL_UART_IRQHandler(&lpuart1);
                break;
#endif

            default:
                break;
        }

        return;
    }

    void HW_UART_DMA_Interrupt_Handler(hw_uart_id_t hw_uart_id)
    {
        switch (hw_uart_id)
        {
#if (CFG_HW_USART1_DMA_TX_SUPPORTED == 1)
            case hw_uart1:
                HAL_DMA_IRQHandler(huart1.hdmatx);
                break;
#endif

#if (CFG_HW_USART2_DMA_TX_SUPPORTED == 1)
            case hw_uart2:
                HAL_DMA_IRQHandler(huart2.hdmatx);
                break;
#endif

#if (CFG_HW_LPUART1_DMA_TX_SUPPORTED == 1)
            case hw_lpuart1:
                HAL_DMA_IRQHandler(lpuart1.hdmatx);
                break;
#endif

            default:
                break;
        }

        return;
    }

    void HAL_UART_MspInit(UART_HandleTypeDef *huart)
    {
#if ( (CFG_HW_USART1_ENABLED == 1) || (CFG_HW_LPUART1_ENABLED == 1) )
        GPIO_InitTypeDef  GPIO_InitStruct = {0};
#endif
        switch ((uint32_t)huart->Instance)
        {
#if (CFG_HW_USART1_ENABLED == 1)
            case (uint32_t)USART1:
      HW_UART_MSP_UART_INIT( huart1, USART1 );
#if (CFG_HW_USART1_DMA_TX_SUPPORTED == 1)
            HW_UART_MSP_TX_DMA_INIT( huart1, USART1 );
#endif
            break;
#endif

#if (CFG_HW_LPUART1_ENABLED == 1)
            case (uint32_t)LPUART1:
      HW_UART_MSP_UART_INIT( lpuart1, LPUART1 );
#if (CFG_HW_LPUART1_DMA_TX_SUPPORTED == 1)
            HW_UART_MSP_TX_DMA_INIT( lpuart1, LPUART1 );
#endif
            break;
#endif

            default:
                break;
        }

        return;
    }

    void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
    {
        switch ((uint32_t)huart->Instance)
        {
#if (CFG_HW_USART1_ENABLED == 1)
            case (uint32_t)USART1:
                    if(HW_huart1RxCb)
                    {
                        HW_huart1RxCb();
                    }
            break;
#endif

#if (CFG_HW_LPUART1_ENABLED == 1)
            case (uint32_t)LPUART1:
                    if(HW_lpuart1RxCb)
                    {
                        HW_lpuart1RxCb();
                    }
            break;
#endif

            default:
                break;
        }

        return;
    }

    void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
    {
        switch ((uint32_t)huart->Instance)
        {
#if (CFG_HW_USART1_ENABLED == 1)
            case (uint32_t)USART1:
                    if(HW_huart1TxCb)
                    {
                        HW_huart1TxCb();
                    }
            break;
#endif

#if (CFG_HW_LPUART1_ENABLED == 1)
            case (uint32_t)LPUART1:
                    if(HW_lpuart1TxCb)
                    {
                        HW_lpuart1TxCb();
                    }
            break;
#endif

            default:
                break;
        }

        return;
    }

    /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
